package com.three.common.message.base.gateway;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.protobuf.InvalidProtocolBufferException;
import com.three.api.common.Condition;
import com.three.api.connection.Connection;
import com.three.api.protocol.Packet;
import com.three.api.spi.push.IPushMessage;
import com.three.common.condition.AwaysPassCondition;
import com.three.common.condition.ScriptCondition;
import com.three.common.condition.TagsCondition;
import com.three.common.memory.PacketFactory;
import com.three.common.message.base.BaseMessage;
import com.three.protocol.BaseModule;
import com.three.utils.JsonUtils;
import io.netty.channel.ChannelFutureListener;

import java.util.Set;

import static com.three.protocol.CommandEnum.Command.GATEWAY_PUSH;

/**
 * Created by Mathua on 2017/5/26.
 */
public final class GatewayPushMessage extends BaseMessage implements IPushMessage {
    private long playerId;
    private int clientType;
    private int timeout;
    private String content;

    private String taskId;
    private Set<String> tags;
    private String condition;

    public GatewayPushMessage(Packet message, Connection connection) {
        super(message, connection);
    }

    @Override
    public void decode(byte[] body) throws InvalidProtocolBufferException {
        BaseModule.GatewayPush_14 bodyData = BaseModule.GatewayPush_14.parseFrom(body);
        playerId = bodyData.getPlayerId();
        clientType = bodyData.getClientType();
        timeout = bodyData.getTimeout();
        content = bodyData.getContent();
        if(bodyData.hasTaskId())
            taskId = bodyData.getTaskId();
        if(bodyData.hasTagsJson())
            tags = decodeSet(bodyData.getTagsJson());
        if(bodyData.hasCondition())
            condition = bodyData.getCondition();
    }

    @Override
    public byte[] encode() {
        BaseModule.GatewayPush_14.Builder builder = BaseModule.GatewayPush_14.newBuilder();
        builder.setPlayerId(playerId);
        builder.setClientType(clientType);
        builder.setTimeout(timeout);
        builder.setContent(content);

        if(taskId != null)
            builder.setTaskId(taskId);
        if(tags != null)
            builder.setTagsJson(encodeSet(tags));
        if(condition != null)
            builder.setCondition(condition);
        return builder.build().toByteArray();
    }

    public static GatewayPushMessage build(Connection connection) {
        Packet packet = PacketFactory.get(GATEWAY_PUSH);
        packet.sessionId = genSessionId();
        return new GatewayPushMessage(packet, connection);
    }

    public GatewayPushMessage setPlayerId(long playerId) {
        this.playerId = playerId;
        return this;
    }

    public GatewayPushMessage setContent(String content) {
        this.content = content;
        return this;
    }

    public GatewayPushMessage setClientType(int clientType) {
        this.clientType = clientType;
        return this;
    }

    public GatewayPushMessage addFlag(byte flag) {
        packet.addFlag(flag);
        return this;
    }

    public GatewayPushMessage setTimeout(int timeout) {
        this.timeout = timeout;
        return this;
    }

    public GatewayPushMessage setTags(Set<String> tags) {
        this.tags = tags;
        return this;
    }

    public GatewayPushMessage setCondition(String condition) {
        this.condition = condition;
        return this;
    }

    @Override
    public boolean isBroadcast() {
        return playerId == 0;
    }

    @Override
    public long getPlayerId() {
        return playerId;
    }

    @Override
    public int getClientType() {
        return clientType;
    }

    @Override
    public Packet getPushPacket() {
        Packet packet = JsonUtils.fromJson(content, Packet.class);
        packet.parseFromBodyTmp();
        return packet;
    }

    @Override
    public int getTimeoutMills() {
        return timeout;
    }

    @Override
    public String getTaskId() {
        return taskId;
    }

    @Override
    public boolean isNeedAck() {
        return packet.hasFlag(Packet.FLAG_BIZ_ACK) || packet.hasFlag(Packet.FLAG_AUTO_ACK);
    }

    @Override
    public byte getFlags() {
        return packet.flags;
    }

    @Override
    public Condition getCondition() {
        if (condition != null) {
            return new ScriptCondition(condition);
        }
        if (tags != null) {
            return new TagsCondition(tags);
        }
        return AwaysPassCondition.I;
    }


    @Override
    public void finalized() {
        this.content = null;
        this.condition = null;
        this.tags = null;
    }

    @Override
    public void send() {
        super.sendRaw();
    }

    @Override
    public void send(ChannelFutureListener listener) {
        super.sendRaw(listener);
    }

    @Override
    public String toString() {
        return "GatewayPushMessage{" +
                "playerId='" + playerId + '\'' +
                ", clientType='" + clientType + '\'' +
                ", timeout='" + timeout + '\'' +
                ", content='" + content + '\'' +
                '}';
    }

    private Set<String> decodeSet(String json) {
        if (json == null) return null;
        return JsonUtils.fromJson(json, new TypeReference<Set<String>>() {
        }.getType());
    }

    private String encodeSet(Set<String> field) {
        return field == null ? null : JsonUtils.toJson(field);
    }
}

